package simulation.simulation;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.plaf.SliderUI;




public class GuiTest extends Panel  {
	private final int FPS = 30;
	private boolean updateLight = false;//boolean to double the time to redraw lightsensor values
	
	//Simulator Simulation; // The simulation that calculates the values.
	
	 BufferedImage  sector;
	 BufferedImage  pacman;
	 BufferedImage  background;
	 BufferedImage map;
	 BufferedImage robot;
	 BufferedImage blackScreen;
	 BufferedImage robotrotated;
	 
	
	 BufferedImage MazePanel= new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
	 BufferedImage MazePanelBuffer = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
	 
	 int[] light1 = new int[100];
	 int[] light2 = new int[100];
	 int[] light3 = new int[100];
	 int[] light4 = new int[100];
	 
	 boolean drawing = false;
	 boolean imagesloaded = false;
	 private int angle = 0;
	private double x;
	private double y;
	private double xOffset = 0;
	private double yOffset = 0;
	 JButton Rightbutton = new JButton("X Right");
	 JButton Leftbutton = new JButton("X Left");
	 JButton Upbutton = new JButton("Y Down");
	 JButton Downbutton = new JButton("Y UP");
	 Timer timer;
	private int[][] walls = { //index with maze[-y][x]
			{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}, 
			{1,1,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1},
			{1,0,0,1,0,1,0,1,1,1,0,1,0,0,1,1,0,1,0,1,0,1,0,0,0,1,1,0,1,1,0,0,1,0,0,0,1,0,1,0,1},
			{1,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1,0,1,0,1,0,1,1,0,1,1,1,0,1,0,1},
			{1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,0,1,1,0,1,0,1,1,0,1},
			{1,0,1,0,0,1,0,1,0,1,0,1,1,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1},
			{1,0,1,0,0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,0,1,1,0,1,0,0,1},
			{1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,1,1},
			{1,0,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,1},
			{1,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1},
			{1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1},
			{1,1,0,1,1,1,0,1,1,0,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,1,1,1,0,0,1,0,1,0,1,0,1,0,1},
			{1,0,1,0,0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,1,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1},
			{1,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,1,0,1,1,1,0,0,0,1,0,0,1,0,1,0,1,0,1,1,0,1,1,0,1},
			{1,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,0,0,1,1},
			{1,0,0,0,1,0,1,1,0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,1,1,0,1},
			{1,1,1,0,1,1,0,1,0,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,1,0,1,0,0,1},
			{1,0,0,1,1,0,0,0,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,1},
			{1,1,0,0,1,0,1,1,1,1,0,0,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1},
			{1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,1,0,1},
			{1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1}};
			
	
	
	
	
	public GuiTest(){
		//random values to test graph
		for (int i = 0; i < 100; i++) {
			light1[i] = (int) ((Math.random() * 20));
			if (Math.random()<0.5)
				light1[i] = -light1[i];
		}
		for (int i = 0; i < 100; i++) {
			light2[i] = (int) ((Math.random() * 20));
			if (Math.random()<0.5)
				light2[i] = -light2[i];
		}
		for (int i = 0; i < 100; i++) {
			light3[i] = (int) ((Math.random() * 20));
			if (Math.random()<0.5)
				light3[i] = -light3[i];
		}
		for (int i = 0; i < 100; i++) {
			light4[i] = (int) ((Math.random() * 20));
			if (Math.random()<0.5)
				light4[i] = -light4[i];
		}
		//end random values.
		
		
		setLayout(new BorderLayout());
		//mouselistener to select robots
		this.addMouseListener(new MouseListener(){

			@Override
			public void mouseClicked(MouseEvent click) {
				System.out.println(click.getX()+ "," + click.getY());
				
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				// TODO Auto-generated method stub
				
			}});
		//FPS is frames per second to draw to screen;
		timer = new Timer(1000/FPS, new ActionListener(){

		
			
			//timer to set when to draw the screen and update values
			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				draw();
				
				if(updateLight){
				//random values for lightsensor, normaly for each robot get this from sensor
				AddLightValue(light1,  (int) (((Math.random()-0.5) * 40)));
				AddLightValue(light2, (int) (((Math.random()-0.5) * 40)));
				AddLightValue(light3,  (int) (((Math.random()-0.5) * 40)));
				AddLightValue(light4,  (int) (((Math.random()-0.5) * 40)));
				updateLight = false;
				}
				else
				updateLight = true;
				
			
				timer.restart();
				
			}});

		timer.start();
		this.setFocusable(true);
		this.requestFocus();
		 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
	        manager.addKeyEventDispatcher(new MyDispatcher());
		loadImages();
		this.setVisible(true);
		//pacman location for testing
		x = 12;
		y = 12;
		this.setPreferredSize(new Dimension(800,600));
		this.validate();
	}
	
	
	/**
	 * add a new value to the history of lightvalues to draw
	 * @param original
	 * 			|Original Array of values
	 * @param newvalue
	 * 			|New Value to add to the end
	 */
	private void AddLightValue(int[] original,int newvalue){
		for (int i = 0; i < original.length-1; i++) {
			original[i] = original[i+1];
		}
		original[original.length-1] = newvalue;
		//return original;
	}
	
	/**
	 * adds to the position of pacman for tests
	 * @param xpos
	 * @param ypos
	 */
	public void setPosition(double xpos, double ypos){
	x += xpos;
	y += ypos;
	}
	
	/**
	 * Loads the images used
	 */
	public void loadImages(){
		 try {                
	          sector = ImageIO.read(new File("simulation/sector_rand.png"));
		  System.out.println("sector_rand found");
	          pacman = ImageIO.read(new File("simulation/pacman.png"));
		  System.out.println("pacman found");
	          background = ImageIO.read(new File("simulation/wood.jpg"));
		  System.out.println("wood found");
	          robot = ImageIO.read(new File("simulation/robot.png"));
		  System.out.println("robot found");
	          blackScreen = ImageIO.read(new File("simulation/DataScreenRobot.png"));
		  System.out.println("DataScreenRobot found");
	          robotrotated =  ImageIO.read(new File("simulation/robot.png"));
	       } catch (IOException ex) {
	            System.out.println("file not found");
	       }
	       imagesloaded = true;
	}
	
	/**
	 * Draws the whole map with walls to an image to avoid overhead work
	 * @param map
	 */
	private void drawMazeImage(Graphics map){
		
		//draw sectors
		for (int i = 0; i < walls.length-1; i++) {
			  for (int j = 0; j < (walls[1].length)/2; j++) {
				double YStartPos = (i)*40;
				double XStartPos = (j)*40;	
			  map.drawImage(sector,(int)XStartPos ,(int)YStartPos,null);
			  }
		}
		
		// draw walls
		map.setColor(new Color(90,43,0));
		int YStart = 0;//(int)(-yOff*40);
		int XStart = 0;//(int)(-xOff*40);
		
		for (int i = 0; i < walls.length; i++) {
			for (int h = 0; h < walls[1].length; h+=2) {
				if(walls[(int) (i)][(int) (h)] == 1){
				
					map.drawLine(h/2*40-1-XStart, (i-1)*40-YStart, (h/2)*40-1-XStart, (i+1-1)*40-YStart);
					map.drawLine(h/2*40-XStart, (i-1)*40-YStart, (h/2)*40-XStart, (i+1-1)*40-YStart);
					map.drawLine(h/2*40+1-XStart, (i-1)*40-YStart, (h/2)*40+1-XStart, (i+1-1)*40-YStart);
				}
				
							}  
			for (int v = 0; v < walls[1].length-1; v+=2) {
				
				if(walls[i][v+1] == 1){
			
					map.drawLine((v/2)*40, (i+1-1)*40-1, (v/2+1)*40, (i+1-1)*40-1);
				map.drawLine((v/2)*40, (i+1-1)*40, (v/2+1)*40, (i+1-1)*40);
					map.drawLine((v/2)*40, (i+1-1)*40+1, (v/2+1)*40, (i+1-1)*40+1);
				}
			}  
		}
		
		map.dispose();
	}
	
	/**
	 * draw method to paint to an image in memory in stead of to the screen
	 */
	private void draw(){
		if (!drawing){
			drawing = true;
			drawMazeToBuffer();
			
			repaint();
			drawing = false;
			
		}
		
	}


	
	
	/**
	 * the drawing code 
	 */
	private void drawMazeToBuffer() {
		MazePanelBuffer = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
		Graphics buffer = MazePanelBuffer.getGraphics();
		buffer.drawImage(background,0,0,300,300,0,0,350,350,null);
		buffer.drawImage(background,300,0,600,300,0,0,350,350,null);
		buffer.drawImage(background,0,300,300,600,0,0,350,350,null);
		buffer.drawImage(background,300,300,600,600,0,0,350,350,null);
		buffer.drawImage(map, 0, 0, 600, 600, (int)(0 + 40*xOffset), (int)(0+40*yOffset), 600+(int)(40*xOffset), 600+(int)(40*yOffset), null);
		
		
		
		buffer.setColor(new Color(255,0,0));
		
		buffer.drawImage(rotate(robot,30),128,120,null);
		buffer.drawString("Robot-1",128,120);
		
		/* When the simulator is working
	 	for each robot not null do
		
		buffer.drawImage(rotate(robot,angle),robot.getX(),robot.getY(),null);
		
		buffer.drawString("Robot-x",robot.getX(),robot.getY());
		*/
		
		//draw pacman at (x,y)
		if (!((int)((x-xOffset)*40)>=600))
		  buffer.drawImage(pacman,(int)((x-xOffset)*40),(int)((y-yOffset)*40),(int)((x-xOffset)*40) +40,(int)((y-yOffset)*40)+40,0,0,pacman.getWidth(),pacman.getHeight(),null);
		
		
		
		//draw the panels background for the data screens
		buffer.drawImage(blackScreen,600,0,800,150,0,0,blackScreen.getWidth(),blackScreen.getHeight(),null);
		buffer.drawImage(blackScreen,600,150,800,300,0,0,blackScreen.getWidth(),blackScreen.getHeight(),null);
		buffer.drawImage(blackScreen,600,300,800,450,0,0,blackScreen.getWidth(),blackScreen.getHeight(),null);
		buffer.drawImage(blackScreen,600,450,800,600,0,0,blackScreen.getWidth(),blackScreen.getHeight(),null);
		buffer.setColor(new Color(255,128,0));
	
		//draw the values of the data, to be switched with real data from the simulator tommorow
		for (int i = 0; i < 4; i++) {
			buffer.setColor(new Color(255,128,0));
			buffer.drawString("Name: Ghost-"+ (i+1),605,20 + i*150);
			buffer.drawString("UltraSonic: 255",605,40 + i*150);
			buffer.drawString("IR: Not Connected",605,60 + i*150);
			buffer.drawString("Light: 26",605,80 + i*150);
			buffer.setColor(new Color(1f,0.5f,0f,0.6f));
			buffer.drawLine(600, 120 + i*150, 800, 120+ i*150);
			buffer.drawLine(600, 140 + i*150, 800, 140+ i*150);
			buffer.drawLine(600, 100 + i*150, 800, 100+ i*150);
		}
		
		//draw the graphs of the lightsensor
		buffer.setColor(new Color(255,128,0));
		for (int i = 1; i < light1.length; i++) {
			buffer.drawLine(599 + 2*i ,120-light1[i-1],600 + 2*i,120-light1[i]);
			buffer.drawLine(599 + 2*i ,270-light2[i-1],600 + 2*i,270-light2[i]);
			buffer.drawLine(599 + 2*i ,420-light3[i-1],600 + 2*i,420-light3[i]);
			buffer.drawLine(599 + 2*i ,570-light4[i-1],600 + 2*i,570-light4[i]);
		}
		
		
		buffer.dispose();
		MazePanel = MazePanelBuffer;
	}
	
	@Override
	public void update(Graphics g){
	       paint(g);
	}
	
	@Override
	public void paint(Graphics g) {
		
		
		if(map == null){
			map = new BufferedImage(40*walls.length, 40*walls[0].length/2, BufferedImage.TYPE_INT_ARGB);
			drawMazeImage(map.getGraphics());
			draw();
		}
	
		g.drawImage(MazePanel,0,0,getWidth(),getHeight(),null);
		
		//g.drawImage(map, 0, 0, 600, 600, (int)(0 + 40*xOffset), (int)(0+40*yOffset), 600+(int)(40*xOffset), 600+(int)(40*yOffset), null);
		//drawBarcode example
		//int i = 5;
		//int j = 6;
		//char[] code = {0,1,1,0,1,0,1,1};
		//drawBarcode(g, i, j, code, true);
		//drawBarcode(g, 12, 2, code, false);
		  
		//drawpacman
		 
		
	//	Graphics2D bot = (Graphics2D) robot.getGraphics();
		//bot.rotate(1.2, robot.getWidth(), robot.getHeight());
		
		//g.drawImage(robotrotated,120,120,null);
		//bot.dispose();
		//if (!((int)((x-xOffset)*40)>=600-40))
		//  g.drawImage(pacman,(int)((x-xOffset)*40),(int)((y-yOffset)*40),(int)((x-xOffset)*40) +40,(int)((y-yOffset)*40)+40,0,0,pacman.getWidth(),pacman.getHeight(),null);
	
	}

	
	
	/**
	 * Draws a barcode at a given position on an image, draws from left to right or up to down.
	 * @param g
	 * 			|The graphics to paint on
	 * @param x
	 * 			|The X position of the tile where to draw the barcode
	 * @param y
	 * 			|The Y position of the tile where to draw the barcode
	 * @param code
	 * 			|The actual barcode to draw
	 * @param hor
	 * 			|Boolean to indicate if the code is horizontal or vertical
	 */
	private void drawBarcode(Graphics g,int x, int y, char[] code,boolean hor){
	
		if (hor){
			for (int i = 0; i < 2*code.length; i+=2) {
				if (code[i/2] == 1)
					g.setColor(new Color(0,0,0));
				else
					g.setColor(new Color(255,255,255));
				
				
			g.drawLine(x*40, (y*40)+12 + i, (x+1)*40 , (y*40)+12 + i);
			g.drawLine(x*40, (y*40)+12 + i+1, (x+1)*40 , (y*40)+12 + i+1);	
			}
			
			
		}else{
			for (int i = 0; i < 2*code.length; i+=2) {
				if (code[i/2] == 1)
					g.setColor(new Color(0,0,0));
				else
					g.setColor(new Color(255,255,255));
				
				
			g.drawLine(x*40+12 + i, (y*40), (x)*40+12 + i , ((y+1)*40));
			g.drawLine(x*40+12 + i+1, (y*40), (x)*40 +12 + i+1, ((y+1)*40));	
			}
		}
	}
	
	
	
	   public static void main(String[] args) {
		  
		  
		   Panel panel = new GuiTest();
		   panel.validate();
		   JFrame jf = new JFrame("Simulation");
		   panel.setFocusable(true);
		   panel.requestFocusInWindow();
		   jf.setFocusable(true);
		   jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	  
		   jf.getContentPane().add(panel);
		   jf.getContentPane().setPreferredSize(new Dimension(800,600));	 
		   jf.validate();
		   jf.pack();
		   jf.setVisible(true);
		  
		   
	    }

	   /**
	    * Rotates an image at a certain angle in degrees
	    * @param img
	    * 			|The Image to rotate
	    * @param angle
	    * 			|The angle to rotate, counterclockwise
	    * @return
	    * 			|A copy of the image rotated;
	    */
	   public static BufferedImage rotate(BufferedImage img, int angle) {  
	       angle = - angle;
		   int w = img.getWidth();  
	        int h = img.getHeight();  
	        BufferedImage dimg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);  
	        Graphics2D g = dimg.createGraphics();  
	       // g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	        g.rotate(Math.toRadians(angle), w/2, h/2);  
	        g.drawImage(img, null, 0, 0);  
	        return dimg;  
	    }  	   

	   
	   
	   
	


	

	
	
	   private class MyDispatcher implements KeyEventDispatcher {
	        @Override
	        public boolean dispatchKeyEvent(KeyEvent e) {
	            if (e.getID() == KeyEvent.KEY_PRESSED) {
	            	int keyCode = e.getKeyCode();
            	    switch( keyCode ) { 
            	        case KeyEvent.VK_Z:
            	        	setPosition(0, -0.1);
            	        	//draw();
            	            break;
            	        case KeyEvent.VK_Q:
            	        	setPosition(-0.1, 0);
            	        	//draw();
            	            break;
            	        case KeyEvent.VK_D:
            	        	setPosition(0.1, 0);
            	        	//draw();
            	            break;
            	        case KeyEvent.VK_S:
            	        	setPosition(0, +0.1);
            	        	//draw();
            	            break;
            	        case KeyEvent.VK_ENTER:
            	        	if (angle >=360)
            	        			angle = 0;
            	        	angle+=10;
            	        	//robotrotated = rotate(robot,angle);
            	        	//draw();
            	            break;
            	    }
	            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
	            	 int keyCode = e.getKeyCode();
	            	    switch( keyCode ) { 
	            	        case KeyEvent.VK_UP:
	            	        	if (yOffset > 0){
	            	            	  yOffset -=1;}
	            	        	//draw();
	            	            break;
	            	        case KeyEvent.VK_DOWN:
	            	        	if (yOffset < (walls.length) - 16){
	            	            	  yOffset +=1;}
	            	        
	            	        	//draw();
	            	            break;
	            	        case KeyEvent.VK_LEFT:
	            	        	if (xOffset >0 ){
	            	            	  xOffset -=1;}
	            	         
	            	        	//draw();
	            	            break;
	            	        case KeyEvent.VK_RIGHT :
	            	        	if (xOffset < (walls[0].length/2) - 15){
	            	            	  xOffset +=1;}
	            	        
	            	          	//draw();
	            	            break;
	            	          
	            	     }
	            } else if (e.getID() == KeyEvent.KEY_TYPED) {
	              //  System.out.println("3test3");
	            }
	            return false;
	        }
	    }






	
}
